package com.se.netty;


import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.ReadTimeoutHandler;
import io.netty.util.concurrent.DefaultEventExecutorGroup;
import io.netty.util.concurrent.DefaultThreadFactory;
import io.netty.util.concurrent.EventExecutorGroup;
import io.netty.util.concurrent.RejectedExecutionHandlers;
import lombok.extern.slf4j.Slf4j;


@Slf4j
public class NettyServer {

    /**
    * @author hdu_huang
    * @date   2018/5/6
    * @desc   Netty 启动器
    */

    public static final EventExecutorGroup eventExecutors = new DefaultEventExecutorGroup(4, new DefaultThreadFactory("business"),1024,  RejectedExecutionHandlers.reject());

    private static final ServerHandler serverHandler = new ServerHandler();

    public static void start(int port) throws Exception {

        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup(0, new DefaultThreadFactory("workerGroup", false));

        try {

            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(bossGroup, workerGroup);

            /**
             *  SO_BACKLOG 服务器处理线程全满时，用于临时存放已完成三次握手的请求的队列的最大长度。如果未设置或所设置的值小于1，Java将使用默认值50。
             *  NoDelay 禁用Nagle 算法 使消息立即发出去，不用等待到一定的数据量才发出去
             *  SO_KEEPALIVE 保持长连接状态
             */

            bootstrap.channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, 1024)
                    .option(ChannelOption.SO_REUSEADDR, true)
                    .childOption(ChannelOption.TCP_NODELAY, true)  // option 没有 TCP_NODELAY
                    .childOption(ChannelOption.SO_KEEPALIVE, true)
//                    .handler(new LoggingHandler(LogLevel.DEBUG))
                    .childHandler(new ChannelInitializer<SocketChannel>(){
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            socketChannel.pipeline().
                                    addLast(new ReadTimeoutHandler(120)).  // 读超时（客户端长时间没有发送数据给服务端）
                                    addLast("logger", new LoggingHandler(LogLevel.DEBUG)).
//                                    addLast(eventExecutors, serverHandler); // 自定义 ChannelHandler
                                    //HttpServerCodec(HttpRequestDecoder和HttpResponseEncoder) 只能解析 请求行 + header  不能解析body
                                    addLast(new HttpServerCodec()).
                                    //WebSocket解编码  new WebSocketServerProtocolHandler("/")
                                    addLast(new HttpObjectAggregator(1024 * 8)).
                                    addLast(serverHandler) // 自定义 ChannelHandler
                            ;
                        }
                    });

            // Start the server.  绑定端口，开始接收进来的连接
            ChannelFuture future = bootstrap.bind(port).sync();

            log.info("NettyServer start success!");

            // Wait until the server socket is closed.
            future.channel().closeFuture().sync();  //此处阻塞(可使用单独方法 @PreDestroy,事件等触发)

            log.info("NettyServer end!!!");
        } finally {
              // spring boot
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }

    }

    public static void main(String[] args) throws Exception {
        System.setProperty("sun.net.useExclusiveBind", "false");
        start(8080);
    }

}
